package com.sys.basics.service.impl;

import cn.hutool.core.util.ArrayUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sys.basics.config.constant.SystemConstant;
import com.sys.basics.entity.SysOrg;
import com.sys.basics.entity.SysRole;
import com.sys.basics.entity.vo.UserOrgRoleVo;
import com.sys.basics.service.SysOrgService;
import com.sys.basics.service.SysUserOrgLkService;
import com.sys.basics.service.SysUserRoleLkService;
import com.sys.basics.utils.ArrayUtils;
import com.sys.basics.utils.CryptoUtils;
import com.sys.basics.utils.ShiroUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.springframework.beans.factory.annotation.Autowired;
import com.sys.basics.entity.SysUser;
import com.sys.basics.dao.SysUserDao;
import com.sys.basics.service.SysUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;


/**
 * @author: ares
 * @date: 2021-09-28
 * @description: 用户表 服务实现类
 */
@Slf4j
@Transactional(rollbackFor = Exception.class)
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserDao, SysUser> implements SysUserService {

    @Autowired
    SysUserDao sysUserDao;

    @Autowired
    SysOrgService sysOrgService;

    @Autowired
    SysUserOrgLkService sysUserOrgLkService;

    @Autowired
    SysUserRoleLkService sysUserRoleLkService;

    @Override
    public SysUser getByUsername(String username) {
        LambdaQueryWrapper<SysUser> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userLambdaQueryWrapper.eq(SysUser::getUsername, username);
        return sysUserDao.selectOne(userLambdaQueryWrapper);
    }

    @Override
    public SysUser getByShortcode(String shortcode) {
        LambdaQueryWrapper<SysUser> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userLambdaQueryWrapper.eq(SysUser::getShortcode, shortcode);
        return sysUserDao.selectOne(userLambdaQueryWrapper);
    }

    @Override
    public SysUser getByAccount(String account) {
        LambdaQueryWrapper<SysUser> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userLambdaQueryWrapper.eq(SysUser::getUsername, account).or().eq(SysUser::getShortcode, account);
        return sysUserDao.selectOne(userLambdaQueryWrapper);
    }

    @Override
    public SysUser getCurrentUserInfoWithRoleAndOrg(Long userId) {
        return sysUserDao.getCurrentUserInfoWithRoleAndOrg(userId);
    }

    @Override
    public boolean modifySelfPwd(SysUser user, String oldPwd, String newPwd) {
        SimpleHash simpleHash = new SimpleHash(SystemConstant.ALGORITHM_NAME, oldPwd, user.getSalt(), SystemConstant.HASH_ITERATIONS);
        String saltOldPwd = simpleHash.toString();
        if (!user.getPassword().equals(saltOldPwd)) {
            throw new IncorrectCredentialsException("旧密码错误");
        }
        return this.modifyPwd(user.getId(), newPwd);
    }

    @Override
    public boolean resetSomeonePwd(Long userId) {
        return this.modifyPwd(userId, SystemConstant.DEFAULT_USER_PWD);
    }

    @Override
    public boolean updateUserDefaultOrg(Long userId, Long orgId) {
        SysUser user = new SysUser();
        user.setId(userId);
        user.setDefaultOrgId(orgId);
        return this.updateById(user);
    }

    @Override
    public IPage<SysUser> getPagesByOrg(Page<SysUser> page, Long orgId, SysUser userParams) {
        return sysUserDao.getPagesByOrg(page, orgId, userParams);
    }

    @Override
    public int batchUpdateStatus(List<Long> userIds, Integer status) {
        UpdateWrapper<SysUser> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set("status", status).in("id", userIds);
        return sysUserDao.update(null, updateWrapper);
    }

    public boolean modifyPwd(Long userId, String pwd) {
        HashMap<String, String> pwdHashMap = CryptoUtils.saltEncrypt(pwd);
        String salt = pwdHashMap.get("salt");
        String saltPassword = pwdHashMap.get("password");
        SysUser user = new SysUser();
        user.setId(userId);
        user.setSalt(salt);
        user.setPassword(saltPassword);
        boolean updated = this.updateById(user);
        if (updated) {
            SysUser userInfo = ShiroUtils.getUserInfo();
            userInfo.setSalt(salt);
            userInfo.setPassword(saltPassword);
            ShiroUtils.updatePrincipal(userInfo);
        }
        return updated;
    }

    @Override
    public int createUserLinkOrgRole(UserOrgRoleVo user) {
        List<Long> orgIds = user.getOrgIds();
        List<Long> roleIds = user.getRoleIds();

        HashMap<String, String> pwdHashMap = CryptoUtils.saltEncrypt(SystemConstant.DEFAULT_USER_PWD);
        SysUser sysUser = new SysUser();
        sysUser.setUsername(user.getUsername());
        sysUser.setDefaultOrgId(orgIds.get(0));
        sysUser.setShortcode(user.getShortcode());
        sysUser.setSalt(pwdHashMap.get("salt"));
        sysUser.setPassword(pwdHashMap.get("password"));
        sysUser.setRealname(user.getRealname());
        sysUser.setNickname(user.getNickname());
        sysUser.setEmail(user.getEmail());
        sysUser.setStatus(user.getStatus());
        sysUser.setMobile(user.getMobile());
        sysUser.setRemark(user.getRemark());
        sysUser.setExpireDate(user.getExpireDate());

        int insertCount = sysUserDao.insert(sysUser);
        Long insertedUserId = sysUser.getId();

        if (orgIds.size() > 0) {
            sysUserOrgLkService.batchCreate(insertedUserId, orgIds);
        }
        if (roleIds.size() > 0) {
            sysUserRoleLkService.batchCreate(insertedUserId, roleIds);
        }

        return insertCount;

    }

    @Override
    public int updateUserLinkOrgRole(UserOrgRoleVo user, Long defaultOrgId) {
        Long userId = user.getId();
        List<Long> orgIds = user.getOrgIds();
        List<Long> roleIds = user.getRoleIds();

        SysUser sysUser = new SysUser();
        sysUser.setId(userId);
        sysUser.setDefaultOrgId(orgIds.get(0));
        sysUser.setShortcode(user.getShortcode());
        sysUser.setRealname(user.getRealname());
        sysUser.setNickname(user.getNickname());
        sysUser.setEmail(user.getEmail());
        sysUser.setStatus(user.getStatus());
        sysUser.setMobile(user.getMobile());
        sysUser.setRemark(user.getRemark());
        sysUser.setExpireDate(user.getExpireDate());

        int updateCount = sysUserDao.updateById(sysUser);

        HashMap<String, List<Long>> dbUserLinkedOrgRole = getLinkedOrgRole(user, defaultOrgId);
        log.info("用户 -> {} 关联的原始组织及角色: {}", user.getId(), dbUserLinkedOrgRole);

        HashMap<String, Object> orgCompareResult = ArrayUtils.arrayCompare(dbUserLinkedOrgRole.get("linkedOrgIds"), orgIds);
        List<Long> missingLinkedOrgIds = (List<Long>) orgCompareResult.get("missing");
        List<Long> excessLinkedOrgIds = (List<Long>) orgCompareResult.get("excess");
        log.info("移除的组织ID: {}", missingLinkedOrgIds);
        log.info("增加的组织ID: {}", excessLinkedOrgIds);
        if (missingLinkedOrgIds.size() > 0) {
            sysUserOrgLkService.batchRemove(userId, missingLinkedOrgIds);
        }
        if (excessLinkedOrgIds.size() > 0) {
            sysUserOrgLkService.batchCreate(userId, excessLinkedOrgIds);
        }


        HashMap<String, Object> roleCompareResult = ArrayUtils.arrayCompare(dbUserLinkedOrgRole.get("linkedRoleIds"), roleIds);
        List<Long> missingLinkedRoleIds = (List<Long>) roleCompareResult.get("missing");
        List<Long> excessLinkedRoleIds = (List<Long>) roleCompareResult.get("excess");
        log.info("移除的角色ID: {}", missingLinkedRoleIds);
        log.info("增加的角色ID: {}", excessLinkedRoleIds);
        if (missingLinkedRoleIds.size() > 0) {
            sysUserRoleLkService.batchRemove(userId, missingLinkedRoleIds);
        }
        if (excessLinkedRoleIds.size() > 0) {
            sysUserRoleLkService.batchCreate(userId, excessLinkedRoleIds);
        }

        return updateCount;
    }

    /**
     * @param user
     * @param defaultOrgId
     * @return
     * @author: ares
     * @date: 2021/10/15 13:51
     * @description: 获取用户关联的组织及角色
     */
    private HashMap<String, List<Long>> getLinkedOrgRole(SysUser user, Long defaultOrgId) {
        SysOrg orgById = sysOrgService.getById(defaultOrgId);
        List<SysOrg> listByUserIdWithRole = sysOrgService.getListByUserIdWithRole(user.getId(), orgById.getOrgType());
        HashMap<String, List<Long>> hashMap = new HashMap<>();
        List<Long> linkedOrgIds = new ArrayList<>();
        List<Long> linkedRoleIds = new ArrayList<>();

        for (SysOrg org : listByUserIdWithRole) {
            linkedOrgIds.add(org.getId());
            List<SysRole> roles = org.getRoles();
            if (!ArrayUtil.isEmpty(roles)) {
                for (SysRole role : roles) {
                    linkedRoleIds.add(role.getId());
                }
            }
        }

        hashMap.put("linkedOrgIds", linkedOrgIds);
        hashMap.put("linkedRoleIds", linkedRoleIds);
        return hashMap;
    }

}
